#include "Guard.h"
#include "../SGD Wrappers/SGD_GraphicsManager.h"
#include "../SGD Wrappers/SGD_AudioManager.h"

#include "GameplayState.h"
#include "BehaviorManager.h"
#include "BaseBehavior.h"
#include "CreateBulletMessage.h"
#include "Player.h"
#include "../SGD Wrappers/SGD_Event.h"
#include "AnimationManager.h"

Guard::Guard() : Listener(this)
{
	RegisterForEvent("ALARM_TRIGGER");
	RegisterForEvent("ALARM_OFF");

	RegisterForEvent("LOST_TARGET");
	RegisterForEvent("TARGET_FOUND");
	RegisterForEvent("STUNNED");
	m_FieldOfView.SetOwner(this);
//	alertSound = &GameplayState::GetInstance()->alertSound;

	//animation.m_strCurrAnimation = "enemy";
	animation.m_strCurrAnimation = "guardRun";
	animation.m_fCurrDuration = 0.0f;
	animation.m_nCurrFrame = 0;


}

Guard::~Guard()
{

}

/*virtual*/ void Guard::Update(float dt)	 /*override*/
{
	if (m_tStunTimer.Update(dt))
	{
		if (currBehavior != nullptr)
		{
			if (m_nAIState == PATROL)
			{

				if (currBehavior->Update(dt, this, *navGraph->GetVertexElement(currPath[m_nCurrPathNode])))
				{
					m_nCurrPathNode++;
					if (m_nCurrPathNode == currPath.size())
					{
						m_nCurrWaypoint++;
						if (m_nCurrWaypoint == m_vWayPoints.size())
							m_nCurrWaypoint = 0;

						navGraph->FindPath(currPath[m_nCurrPathNode - 1], m_vWayPoints[m_nCurrWaypoint], currPath);
						m_nCurrPathNode = 0;

					}
				}
			}
			else if (m_nAIState == TO_ALARM)
			{
				if (currBehavior->Update(dt, this, *navGraph->GetVertexElement(currPath[m_nCurrPathNode])))
				{

					m_nCurrPathNode++;
					if (m_nCurrPathNode == currPath.size())
					{
						navGraph->FindPath(currPath[m_nCurrPathNode - 1], homeNode, currPath);
						m_nCurrPathNode = 0;


						m_nCurrWaypoint++;
						if (m_nCurrWaypoint == m_vWayPoints.size())
							m_nCurrWaypoint = 0;
						m_nAIState = GO_HOME;
					}
				}
			}
			else if (m_nAIState == GO_HOME)
			{
				if (currBehavior->Update(dt, this, *navGraph->GetVertexElement(currPath[m_nCurrPathNode])))
				{
					m_nCurrPathNode++;
					if (m_nCurrPathNode == currPath.size())
					{
						m_nCurrPathNode = 0;
						RetrieveBehavior("wait");
						m_nAIState = WAIT;
					}
				}
			}
			else if (m_nAIState == SEARCHING)
			{
				if (currBehavior->Update(dt, this, m_ptLastKnownPos))
				{
					m_nAIState = GO_HOME;
					RetrieveBehavior("runTo");
				}
			}
			else if (m_nAIState == ALERT)
			{
				currBehavior->Update(dt, this, m_pTarget->GetPosition());
			}
			else if (m_nAIState == WAIT)
			{
				currBehavior->Update(dt, this, SGD::Point());
			}
		}
	}

	EnemyUnit::Update(dt);

	AnimationManager::GetInstance()->Update(this->animation, dt);
}

/*virtual*/ void Guard::HandleEvent(const SGD::Event* pEvent)
{
	if (pEvent->GetEventID() == "LOST_TARGET")
	{

		unsigned int closestNode;
		float distanceToNode = 70000;
		for (unsigned int i = 0;  i < navGraph->size();  i++)
		{
			
			SGD::Point temp = *navGraph->GetVertexElement(i);
			 float newDistance = (temp - m_ptPosition).ComputeLength();
			
			 if (newDistance < distanceToNode)
			 {
				 distanceToNode = newDistance;
				 closestNode = i;
			 }
			
		}

		m_nAIState = TO_ALARM;
		navGraph->FindPath(closestNode, alarmNode, currPath);
		m_nCurrPathNode = 0;

		RetrieveBehavior("runTo");
		SetAnimation("guardRun");
	}
	else if (pEvent->GetEventID() == "TARGET_FOUND")
	{
		m_nAIState = ALERT;
		RetrieveBehavior("hostile");
		SetAnimation("guardRun");

	}
	else if (pEvent->GetEventID() == "ALARM_TRIGGER")
	{
		SetAnimation("guardRun");
		unsigned int closestNode;
		float distanceToNode = 70000;
		for (unsigned int i = 0; i < navGraph->size(); i++)
		{

			SGD::Point temp = *navGraph->GetVertexElement(i);
			float newDistance = (temp - m_ptPosition).ComputeLength();

			if (newDistance < distanceToNode)
			{
				distanceToNode = newDistance;
				closestNode = i;
			}

		}

		m_nAIState = GO_HOME;
		navGraph->FindPath(closestNode, homeNode, currPath);
		m_nCurrPathNode = 0;
		RetrieveBehavior("runTo");
		SetAnimation("guardRun");
	}
	else if (pEvent->GetEventID() == "STUNNED")
	{
		SetAnimation("guardTakedown");
		m_tStunTimer.AddTime(5);
	}
	else if (pEvent->GetEventID() == "ALARM_OFF" || pEvent->GetEventID() == "BACK_TO_PATROL")
	{
		if (m_nAIState != PATROL && m_nAIState != TO_ALARM)
		{
			unsigned int closestNode;
			float distanceToNode = 70000;
			for (unsigned int i = 0; i < navGraph->size(); i++)
			{

				SGD::Point temp = *navGraph->GetVertexElement(i);
				float newDistance = (temp - m_ptPosition).ComputeLength();

				if (newDistance < distanceToNode)
				{
					distanceToNode = newDistance;
					closestNode = i;
				}

			}

			m_nAIState = PATROL;
			navGraph->FindPath(m_nCurrPathNode, m_vWayPoints[0], currPath);
			m_nCurrPathNode = 0;
			SetAnimation("guardWalk");
			RetrieveBehavior("move");
		}
	}

}
/*virtual*/ void Guard::HandleCollision(const IBase* pOther) /*override*/
{
	if (pOther->GetType() == OBJ_PLAYER)
	{
			// collides with the player when taser is out
			if (this->GetAnimation() == "guardTaser")
			{
				SGD::Event hitPlayer = { "HIT", nullptr, this };
				hitPlayer.SendEventNow(m_pTarget);
			}
			else if (dynamic_cast<const Player*>(pOther)->GetAttackState() == 0)
			{
				m_nAIState = ALERT;
				RetrieveBehavior("hostile");
			}
			else
			{
				m_nAIState = ALERT;
				RetrieveBehavior("hostile");
			}
	}


	else if (pOther->GetType() == OBJ_TRIGGER || pOther->GetType() == OBJ_PLAYERCOLLISION)
	{

	}
	else
		MovingObject::HandleCollision(pOther);
}

void Guard::RetrieveBehavior(std::string name)
{

	if (currBehavior != nullptr)
		currBehavior = nullptr;
	
	currBehavior = BehaviorManager::GetInstance()->GetBehaviors()[name];
}

/*virtual*/ void Guard::Attack() /*override*/
{
	m_tShotTimer.AddTime(1.0f);




	// taser is NOT out, cooldown is over, and player is in range

	if (this->GetAnimation() != "guardTaser")
	{

		this->SetAnimation("guardTaser");
	}
}